
#include "gd32f30x.h" 
#include "i2c_master.h"

#define I2C0_SPEED              100000
#define I2C0_SLAVE_ADDRESS7     0xA0

/*!
    \brief      configure the GPIO ports
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void i2c_gpio_config(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
//	    /* enable I2C0 clock */
    rcu_periph_clock_enable(RCU_I2C0);

    /* connect PB6 to I2C0_SCL */
    /* connect PB7 to I2C0_SDA */
	gpio_pin_remap_config(GPIO_I2C0_REMAP, ENABLE);
    gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_8 | GPIO_PIN_9);
}

/*!
    \brief      configure the I2C0 interfaces
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void i2c_config(void)
{
    /* enable I2C clock */
    rcu_periph_clock_enable(RCU_I2C0);
    /* configure I2C clock */
    i2c_clock_config(I2C0,I2C0_SPEED,I2C_DTCY_2);
    /* configure I2C address */
    i2c_mode_addr_config(I2C0,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,I2C0_SLAVE_ADDRESS7);
    /* enable I2C0 */
    i2c_enable(I2C0);
    /* enable acknowledge */
    i2c_ack_config(I2C0,I2C_ACK_ENABLE);
}



static uint8_t i2c_wait_flag(uint32_t i2c_periph, uint32_t flag, FlagStatus status, uint32_t time){
	uint32_t count = time;
	
    while(i2c_flag_get(i2c_periph, flag) != status){
		if(count == 0){
			return 1;
		}
		count--;
	}
	
	return 0;
}

#define i2c_wait_flag_return(i2c, flag, status)		\
do{		\
	if(i2c_wait_flag(i2c, flag, status, 100000))  return 1;		\
}while(0)

#define i2c_wait_flag_set(i2c, flag)	i2c_wait_flag_return(i2c, flag, SET)
#define i2c_wait_flag_reset(i2c, flag)	i2c_wait_flag_return(i2c, flag, RESET)

uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* buffer, uint16_t length)
{
    /* wait until I2C bus is idle */
    i2c_wait_flag_reset(I2C0, I2C_FLAG_I2CBSY);
	
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);
    
    /* wait until SBSEND bit is set */
    i2c_wait_flag_set(I2C0, I2C_FLAG_SBSEND);
	
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C0, devaddr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
    i2c_wait_flag_set(I2C0, I2C_FLAG_ADDSEND);
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
//	    while( SET != i2c_flag_get(I2C0, I2C_FLAG_TBE));
    i2c_wait_flag_set(I2C0, I2C_FLAG_TBE);
    /* send the EEPROM's internal address to write to : only one byte address */
    i2c_data_transmit(I2C0, regaddr);
    
    /* wait until BTC bit is set */
//	    while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
    i2c_wait_flag_set(I2C0, I2C_FLAG_BTC);
	
    /* while there is data to be written */
    while(length--){  
        i2c_data_transmit(I2C0, *buffer);
        
        /* point to the next byte to be written */
        buffer++; 
        
        /* wait until BTC bit is set */
//	        while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
	    i2c_wait_flag_set(I2C0, I2C_FLAG_BTC);
    }
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C0);
    
    /* wait until the stop condition is finished */
    while(I2C_CTL0(I2C0)&0x0200);
	return 0;
}


uint8_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* buffer, uint16_t length)
{  
	uint32_t i = 100000;
	
    /* wait until I2C bus is idle */
//	    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));
	i2c_wait_flag_reset(I2C0, I2C_FLAG_I2CBSY);

    if(2 == length){
        i2c_ackpos_config(I2C0,I2C_ACKPOS_NEXT);
    }
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);
    
    /* wait until SBSEND bit is set */
//	    while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
    i2c_wait_flag_set(I2C0, I2C_FLAG_SBSEND);
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C0, devaddr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
//	    while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
    i2c_wait_flag_set(I2C0, I2C_FLAG_ADDSEND);
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
//	    while(SET != i2c_flag_get( I2C0 , I2C_FLAG_TBE));
    i2c_wait_flag_set( I2C0 , I2C_FLAG_TBE);
    /* send the EEPROM's internal address to write to */
    i2c_data_transmit(I2C0, regaddr);  
    
    /* wait until BTC bit is set */
//	    while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
    i2c_wait_flag_set(I2C0, I2C_FLAG_BTC);
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);
    
    /* wait until SBSEND bit is set */
//	    while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
    i2c_wait_flag_set(I2C0, I2C_FLAG_SBSEND);
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C0, devaddr, I2C_RECEIVER);

    if(length < 3){
        /* disable acknowledge */
        i2c_ack_config(I2C0,I2C_ACK_DISABLE);
    }
    
    /* wait until ADDSEND bit is set */
//	    while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
    i2c_wait_flag_set(I2C0, I2C_FLAG_ADDSEND);
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
    
    if(1 == length){
        /* send a stop condition to I2C bus */
        i2c_stop_on_bus(I2C0);
    }
    
    /* while there is data to be read */
    while(length){
        if(3 == length){
            /* wait until BTC bit is set */
//	            while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
			i2c_wait_flag_set(I2C0, I2C_FLAG_BTC);
            /* disable acknowledge */
            i2c_ack_config(I2C0,I2C_ACK_DISABLE);
        }
        if(2 == length){
            /* wait until BTC bit is set */
//	            while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
			i2c_wait_flag_set(I2C0, I2C_FLAG_BTC);
            /* send a stop condition to I2C bus */
            i2c_stop_on_bus(I2C0);
        }
        
        /* wait until the RBNE bit is set and clear it */
        if(i2c_flag_get(I2C0, I2C_FLAG_RBNE)){
            /* read a byte from the EEPROM */
            *buffer = i2c_data_receive(I2C0);
            
            /* point to the next location where the byte read will be saved */
            buffer++; 
            
            /* decrement the read bytes counter */
            length--;

			i = 100000;
        }
		if(i == 0){
			return 1;
		}
		--i;
    }
    
    /* wait until the stop condition is finished */
    while(I2C_CTL0(I2C0)&0x0200);
    
    /* enable acknowledge */
    i2c_ack_config(I2C0,I2C_ACK_ENABLE);

    i2c_ackpos_config(I2C0,I2C_ACKPOS_CURRENT);
	return 0;
}



#if 0
uint8_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, uint8_t* buffer, uint16_t length)
{
    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C0, devaddr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
    while( SET != i2c_flag_get(I2C0, I2C_FLAG_TBE));
    
    /* send the EEPROM's internal address to write to : only one byte address */
    i2c_data_transmit(I2C0, regaddr);
    
    /* wait until BTC bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
    
    /* while there is data to be written */
    while(length--){  
        i2c_data_transmit(I2C0, *buffer);
        
        /* point to the next byte to be written */
        buffer++; 
        
        /* wait until BTC bit is set */
        while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
    }
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2C0);
    
    /* wait until the stop condition is finished */
    while(I2C_CTL0(I2C0)&0x0200);
	return 0;
}


uint8_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* buffer, uint16_t length)
{  
    /* wait until I2C bus is idle */
    while(i2c_flag_get(I2C0, I2C_FLAG_I2CBSY));

    if(2 == length){
        i2c_ackpos_config(I2C0,I2C_ACKPOS_NEXT);
    }
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C0, devaddr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
    while(SET != i2c_flag_get( I2C0 , I2C_FLAG_TBE));

    /* send the EEPROM's internal address to write to */
    i2c_data_transmit(I2C0, regaddr);  
    
    /* wait until BTC bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(I2C0);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(I2C0, devaddr, I2C_RECEIVER);

    if(length < 3){
        /* disable acknowledge */
        i2c_ack_config(I2C0,I2C_ACK_DISABLE);
    }
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2C0,I2C_FLAG_ADDSEND);
    
    if(1 == length){
        /* send a stop condition to I2C bus */
        i2c_stop_on_bus(I2C0);
    }
    
    /* while there is data to be read */
    while(length){
        if(3 == length){
            /* wait until BTC bit is set */
            while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));

            /* disable acknowledge */
            i2c_ack_config(I2C0,I2C_ACK_DISABLE);
        }
        if(2 == length){
            /* wait until BTC bit is set */
            while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
            
            /* send a stop condition to I2C bus */
            i2c_stop_on_bus(I2C0);
        }
        
        /* wait until the RBNE bit is set and clear it */
        if(i2c_flag_get(I2C0, I2C_FLAG_RBNE)){
            /* read a byte from the EEPROM */
            *buffer = i2c_data_receive(I2C0);
            
            /* point to the next location where the byte read will be saved */
            buffer++; 
            
            /* decrement the read bytes counter */
            length--;
        } 
    }
    
    /* wait until the stop condition is finished */
    while(I2C_CTL0(I2C0)&0x0200);
    
    /* enable acknowledge */
    i2c_ack_config(I2C0,I2C_ACK_ENABLE);

    i2c_ackpos_config(I2C0,I2C_ACKPOS_CURRENT);
	return 0;
}

#endif 

void i2c_init(void)
{
	i2c_gpio_config();
	i2c_config();
}


